package com.swt.gap.service.impl;

import com.alibaba.fastjson.JSON;
import com.swt.gap.dao.ModelClassMapper;
import com.swt.gap.dao.ModelMapper;
import com.swt.gap.model.entity.Model;
import com.swt.gap.model.entity.ModelClass;
import com.swt.gap.model.entity.ModelWithBLOBs;
import com.swt.gap.model.vo.Model2VO;
import com.swt.gap.model.vo.ModelByClassVO;
import com.swt.gap.model.vo.graph.GraphModel;
import com.swt.gap.service.Model2Service;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * 请填写说明
 *
 * @author sx
 * @date 2020/7/21 16:22
 */
@Service
public class Model2ServiceImpl implements Model2Service {

    private final ModelMapper modelMapper;
    private final ModelClassMapper modelClassMapper;

    public Model2ServiceImpl(ModelMapper modelMapper, ModelClassMapper modelClassMapper) {
        this.modelMapper = modelMapper;
        this.modelClassMapper = modelClassMapper;
    }

    @Override
    public Integer saveModel(Model2VO record) {
        ModelWithBLOBs model = transferData(record);
        int retValue = modelMapper.insertSelective(model);
        model.setModelId(model.getModelId());
        return retValue;
    }

    @Override
    public Model2VO getModelById(Integer modelId) {
        Model2VO retValue = new Model2VO();
        ModelWithBLOBs model = modelMapper.selectByPrimaryKey(modelId);
        if (null == model) {
            return null;
        }
        BeanUtils.copyProperties(model, retValue);
        retValue.setGraphModels(JSON.parseArray(model.getGraphModel(), GraphModel.class));
        return retValue;
    }

    @Override
    public Integer updateModel(Model2VO model) {
        return modelMapper.updateByPrimaryKeySelective(transferData(model));
    }

    @Override
    public List<ModelByClassVO> listModel() {
        List<ModelByClassVO> retValue = new ArrayList<>();
        List<ModelClass> modelClasses = modelClassMapper.selectAll();
        modelClasses.forEach(modelClass -> {
            ModelByClassVO modelByClassVO = new ModelByClassVO();
            modelByClassVO.setModelClassId(modelClass.getModelClassId());
            modelByClassVO.setClassName(modelClass.getClassName());
            modelByClassVO.setModels(modelMapper.selectByClassId(modelClass.getModelClassId()));
            retValue.add(modelByClassVO);
        });
        return retValue;
    }

    @Override
    public Model2VO getRecommendModel(List<String> header) {
        Integer matchModelId = 0;
        int sameHeaderCount = 0;
        List<ModelByClassVO> allModels = listModel();
        for(ModelByClassVO classModel : allModels) {
            for (Model model : classModel.getModels()) {
                List<String> modelFields = new ArrayList<>(Arrays.asList(model.getMatchField().split(",")));
                modelFields.retainAll(header);
                if(modelFields.size() > sameHeaderCount) {
                    sameHeaderCount = modelFields.size();
                    matchModelId = model.getModelId();
                }
            }
        }
        if(!matchModelId.equals(0)) {
            return getModelById(matchModelId);
        } else {
            return null;
        }
    }

    private ModelWithBLOBs transferData(Model2VO record) {
        ModelWithBLOBs model = new ModelWithBLOBs();
        BeanUtils.copyProperties(record, model);

        List<GraphModel> graphModels = record.getGraphModels();
        Optional.ofNullable(graphModels).ifPresent(listGraphModels -> {
            Set<String> matchFields = getMatchFieldsFromModel(listGraphModels);
            model.setGraphModel(JSON.toJSONString(listGraphModels));
            model.setMatchField(StringUtils.join(matchFields
                    .stream()
                    .filter(field -> !StringUtils.isEmpty(field))
                    .collect(Collectors.toSet()),","));

        });
        return model;
    }

    public Set<String> getMatchFieldsFromModel(List<GraphModel> listGraphModel) {
        Set<String> matchFields = new HashSet<>();
        listGraphModel.forEach(graphModel -> {
            graphModel.getStartNodeConfig().getNodePropertyConfigs().forEach(property -> matchFields.add(property.getPropertyField()));
            graphModel.getEndNodeConfig().getNodePropertyConfigs().forEach(property -> matchFields.add(property.getPropertyField()));
            graphModel.getRelationshipConfig().getRelationshipPropertyConfigs().forEach(property -> matchFields.add(property.getPropertyField()));
        });
        matchFields.remove("");
        return matchFields;
    }
}
